var _DEBUG = true;
var _TRACE = true;

function debug(str) {
	if( _DEBUG ) console.log(str);
}

function trace(str) {
	if( _TRACE ) console.log(str);
}

ArcoSettings = Backbone.Model.extend({
	defaults : {
		deckSize : 50,
		handSize : 5,
		discardPileSize : 3,
		sound_on  : true
	},
	initialize : function() {
	}
});

var _settings = new ArcoSettings();

ArcoLayout = Backbone.NestedModel.extend({
	defaults : {
		player1Hand : { top : 300, left : 10, width : 500, height : 150 },
		player1Cards : [
			{ top : 480, left : 10 },
			{ top : 480, left : 120 },
			{ top : 480, left : 230 },
			{ top : 480, left : 340 },
			{ top : 480, left : 450 }
		],
		player1Quarry : {
			size : { width : 100, height : 100 },
			position : { top : 120, left: 10 },
			style : { background : "#ffa0a0" },
			classes : [ "ArcoObject", "Player1", "Quarry" ]
		},
		player1Magic : {
			size : { width : 100, height : 100 },
			position : { top : 240, left : 10 },
			style : { background : "#a0a0ff" },
			classes : [ "ArcoObject", "Player1", "Magic"  ]
		},
		player1Dungeon : {
			size : { width : 100, height : 100 },
			position: { top : 360, left : 10 },
			style : { background : "#a0ffa0" },
			classes : [ "ArcoObject", "Player1", "Dungeon" ]
		},
		player2Quarry : {
			size : { width : 100, height : 100 },
			position : { top : 120, right: 10 },
			style : { background : "#ffa0a0" },
			classes : [ "ArcoObject", "Player2", "Quarry" ]
		},
		player2Magic : {
			size : { width : 100, height : 100 },
			position : { top : 240, right : 10 },
			style : { background : "#a0a0ff" },
			classes : [ "ArcoObject", "Player2", "Magic" ]
		},
		player2Dungeon : {
			size : { width : 100, height  : 100 },
			position : { top : 360, right : 10 },
			style : { background : "#a0ffa0" },
			classes : [ "ArcoObject", "Player2", "Dungeon" ]
		},
		
		player1Tower : {
			size: { height : 220, width: 100 },
			position : { top : 240, left : 150 },
			style : { background : "#b0b0b0" },
			classes : [ "ArcoObject", "Player1", "Tower" ]
		},
		player2Tower : {
			size : {height : 220, width: 100 },
			position : { top : 240, right : 150 },
			style : { background : "#b0b0b0" },
			classes : [ "ArcoObject", "Player2", "Tower" ]
		},
		
		player1Wall : {
			size : { height : 220, width : 100 },
			position : { top : 240, left : 250 },
			style : { background : "#b0b0b0" },
			classes : [ "ArcoObject", "Player1", "Wall" ]
		},
		player2Wall : {
			size : { height : 220, width : 100 },
			position : { top : 240, right : 250 },
			style : { background : "#b0b0b0" },
			classes : [ "ArcoObject", "Player2", "Wall" ]
		},
		
		player1Deck : {
			size : { height: 100, width : 100 },
			position : { top: 120, left : 150 },
			style : { background : "#ffa0ff" },
			classes : [ "ArcoObject", "Player1", "Deck" ]
		},
		
		arcoCard : {
			size : { height: 150, width : 100 },
			initialPosition : { top: 120, left : 150 },
			/* style : { background : "#a0ffff" }, */
			initialClasses : [ "ArcoObject", "Player1", "ArcoCard" ]
		},
		
		cardPlay : {
			position : { top : 300, left : 300 }
		},
		
		player2CardPlay : {
			position : { top : 300, right : 0 }
		},
		
		discardCards : [
			{ top : 10, left : 10 },
			{ top : 10, left : 120 },
			{ top : 10, left : 230 },
			{ top : 10, left : 340 },
			{ top : 10, left : 450 }
		],
		
		gameState : {
			position : { top : 10, left : 10 },
			size : { height: 25, width: 100 },
			style : {},
			classes : [ "ArcoObject", "GameState" ]
		},
	},
	initialize : function() {
		this.calculate();
	},
	calculate : function() {
		debug("calculating positions");
		var width = $(window).width();
		var height = $(window).height();
		debug(width + "x" + height);
		
		if( width > height ) {
			this.calculateLandcape();
		} else {
			this.calculatePortrait();
		}
		
		if( _game ) {
			_game.fixPlayer1Cards({
				duration : 0
			});
			_game.fixDiscardPile({
				duration : 0
			});
		}
	},
	calculateLandcape : function() {
		debug("calculating landscape");
		var width = $(window).width();
		var height = $(window).height();
		
		var padding = 5;
		
		// set the global font size to something relative to the window size
		var fontSize = parseInt(_.min([ width / 68, height / 41]));
		$("body").css({ fontSize : fontSize });
		
		// cards should be roughly the bottom third of the display		
		var cardHeight = parseInt((height-padding*4) / 3);
		var cardTop = cardHeight * 2 + padding * 3;
		var cardWidth = parseInt(2 / 3 * cardHeight);
		
				
		this.set({
			"cardPlay.position.top" : parseInt(height / 2 - cardHeight / 2),
			"cardPlay.position.left" : parseInt(width / 2 - cardWidth / 2)
		});
		
		var arcoCard = this.get("arcoCard");
		//arcoCard.size = { width : cardWidth, height : cardHeight };
		//this.set({ "arcoCard" : arcoCard });
		this.set({
			"arcoCard.size.width" : cardWidth,
			"arcoCard.size.height" : cardHeight
		});
		
		var player1Cards = this.get("player1Cards");
		var handSize = _settings.get("handSize");
		
		for( var i=0 ; i<player1Cards.length ; i++ ) {
			player1Cards[i].top = cardTop;
			player1Cards[i].left = parseInt((width / (handSize+1)) * (i+1) - cardWidth / 2)
		}
		this.set({ "player1Cards" : player1Cards });
		
		// resources take up roughly 2/3 of the top of the screen, evenly spaced
		// each resource is about 1/4 of that space
		var resourceHeight = parseInt((height / 3 * 2) / 4);
		var resourceOffset = resourceHeight / 2;
		
		// they take up about 1/8 of the horizontal space
		var resourceWidth = parseInt(width / 8);
		
		this.set({ "player1Quarry.size" : { width : resourceWidth, height : resourceHeight } });
		this.set({ "player1Quarry.position" : { top : resourceOffset, left : padding } });
		
		this.set({ "player2Quarry.size" : { width : resourceWidth, height : resourceHeight } });
		this.set({ "player2Quarry.position" : { top : resourceOffset, right : padding } });
		
		this.set({ "player1Magic.size" : { width : resourceWidth, height : resourceHeight } });
		this.set({ "player1Magic.position" : { top : resourceOffset + resourceHeight + padding, left : padding } });
		
		this.set({ "player2Magic.size" : { width : resourceWidth, height : resourceHeight } });
		this.set({ "player2Magic.position" : { top : resourceOffset + resourceHeight + padding, right : padding } });
		
		this.set({ "player1Dungeon.size" : { width : resourceWidth, height : resourceHeight } });
		this.set({ "player1Dungeon.position" : { top : resourceOffset + (resourceHeight + padding) * 2, left : padding } });
		
		this.set({ "player2Dungeon.size" : { width : resourceWidth, height : resourceHeight } });
		this.set({ "player2Dungeon.position" : { top : resourceOffset + (resourceHeight + padding) * 2, right : padding } });
		
		// the deck is largely dependent on card size and the resources
		var deckPositionLeft = padding * 2 + resourceWidth;
		this.set({ "player1Deck.size" : { width : cardWidth, height : cardHeight } });
		this.set({ "player1Deck.position" : { top : padding , left : deckPositionLeft } });
		
		this.set({ "arcoCard.initialPosition" : { top : padding , left : deckPositionLeft } });
		this.set({ "player2CardPlay.position" : { top : parseInt(height / 2 - cardWidth / 2), left : width - cardWidth } });
		
		// discarded cards are to the right of the deck
		var discardCards = this.get("discardCards");
		for( var i=0 ; i<discardCards.length ; i++ ) {
			discardCards[i] = { top : padding, left : (deckPositionLeft + (cardWidth+padding) * (i+1)) };
		}
		this.set({ "discardCards" : discardCards });
		
		// player 1 towers go to the right of the resources, just above the hadn
		// they're roughly 1/16 the size of the screen
		var towerWidth = parseInt(width / 16);
		var towerTop = padding * 2 + cardHeight;
		var towerLeft = padding*2 + resourceWidth;
		var towerBottom = cardTop - padding;
		var towerHeight = parseInt(towerBottom - towerTop);
		this.set({ "player1Tower.size" : { width : towerWidth, height : towerHeight } });
		this.set({ "player1Tower.position" : { top : towerTop , left : towerLeft } });
		
		this.set({ "player1Wall.size" : { width : towerWidth, height : towerHeight } });
		this.set({ "player1Wall.position" : { top : towerTop, left : towerLeft + towerWidth + padding } });
		
		towerLeft = width - padding * 2 - resourceWidth - towerWidth;
		this.set({ "player2Tower.size" : { width : towerWidth, height : towerHeight } });
		this.set({ "player2Tower.position" : { top : towerTop, left : towerLeft } });
		
		this.set({ "player2Wall.size" : { width : towerWidth, height : towerHeight } });
		this.set({ "player2Wall.position" : { top : towerTop, left : towerLeft - padding - towerWidth } });
		
		this.set({ "gameState.position" : { top : padding, left : padding } } );
		this.set({ "gameState.size" : { width : resourceWidth, height : resourceOffset - padding * 2 } });
		this.set({ "gameState.style.lineHeight" : (resourceOffset - padding * 2) + "px" });
	},
	calculatePortrait : function() {
		var width = $(window).width();
		var height = $(window).height();
	}
});

var _layout = new ArcoLayout();
_.extend(_layout, Backbone.Events);

var _object_id = 1;

ArcoObject = Backbone.Model.extend({
	defaults : {
		id : 0
	},
	initialize : function() {
		this.set({ "id" : _object_id++ });
	}
});

ArcoObjectView = Backbone.View.extend({
	initialize : function() {
		this.$el = $("<div></div>");
		
		var self=this;
		this.$el.on("tap", function(e) { self.tap(self, e); } );
		this.$el.on("taphold", function(e) { self.taphold(self, e); } );
		
		if( _layout.get(this.model.get("layout_id")) ) {
			debug("listening to " + this.model.get("layout_id"));
			this.listenTo(_layout, "change:" + this.model.get("layout_id"), this.layoutChange);
		}
	},
	tap : function(obj, e) {
	},
	taphold : function(obj, e) {
	},
	doLayout : function() {
		this.initialLayout();
	},
	applyStyles : function(styles) {
		this.$el.css(styles);
	},
	applyClasses : function(classes) {
		this.$el.attr("class", classes.join(" "));
	},
	initialLayout : function() {
		var layout = _layout.get(this.model.get("layout_id"));
		if( typeof layout == "undefined" ) {
			debug("no layout found for " + this.model.get("name") + ", layout " + this.model.get("layout_id") );
			return;
		}

		var position = {}, size = {}, style = {}, classes = [];
		
		if( layout.position ) {
			position = layout.position;		
			_.extend(position, {
				duration : 0
			});
			this.moveTo(position);
		} else if( layout.initialPosition ) {
			position = layout.initialPosition;
			_.extend(position, {
				duration : 0
			});
			this.moveTo(position);
		}
				
		if( layout.style ) {
			_.extend(style, layout.style);
			this.applyStyles(style);
		} else if( layout.initialStyle ) {
			_.extend(style, layout.initialStyle);
			this.applyStyles(style);
		}
		
		if( layout.size ) {
			_.extend(size, layout.size);
			this.resize(size);	
		} else if( layout.initialSize ) {
			_.extend(size, layout.initialSize);
			this.resize(size);
		}
		
		if( layout.classes ) {
			classes = layout.classes;
			this.applyClasses(classes);
		} else if( layout.initialClasses ) {
			classes = layout.initialClasses;
			this.applyClasses(classes);
		}
	},
	layoutChange : function() {
		var layout = _layout.get(this.model.get("layout_id"));
		if( typeof layout == "undefined" ) {
			debug("no layout found for " + this.model.get("name") + ", layout " + this.model.get("layout_id") );
			return;
		}
		
		// make the move instant
		var position = { duration : 0}, size = {}, style = {}, classes = [];
		
		if( layout.position ) {
			position = layout.position;		
			this.moveTo(position);
		}
				
		if( layout.style ) {
			_.extend(style, layout.style);
			this.applyStyles(style);
		}
		
		if( layout.size ) {
			_.extend(size, layout.size);
			this.resize(size);	
		}
		
		if( layout.classes ) {
			classes = layout.classes;
			this.applyClasses(classes);
		}
	},
	addTo : function(el) {
		this.$el.appendTo($(el));
	},
	moveTo : function(options) {
		options = _.extend({
			duration : 1000,
			easing : "linear",
			callback : function() { }
		}, options);
		this.$el.animate(options, options.duration, options.easing, options.callback);
		return this;
	},
	resize : function(options) {
		options = _.extend({
			width : this.model.get("width"),
			height : this.model.get("height")
		}, options);
		this.$el.css({
			width : options.width,
			height : options.height
		});
	},
	setColor : function(color) {
		this.$el.css({ border: "solid 1px " + color });
	},
	addClass : function(cls) {
		this.$el.addClass(cls);
	},
	removeClass : function(cls) {
		this.$el.removeClass(cls);
	}
});

ArcoElements = Backbone.Collection.extend({
	model : ArcoObject
});

ArcoResource = ArcoObject.extend({
	defaults : {
		name : "Resource",
		layout_id : null,
		production : 0,
		amount : 0
	},
	initialize : function() {
		this.view = new ArcoResourceView({ model : this });
		ArcoObject.prototype.initialize.call(this);
		
		debug("creating a model for " + this.get("name") + " (" + this.get("id") + ")");
	},
	onUpdateProduction : function(evt, amt, other) {
		this.set({ production : amt });
	},
	onUpdateAmount : function(evt, amt, other) {
		this.set({ amount : amt });
	}
});

ArcoResourceView = ArcoObjectView.extend({
	initialize : function() {
		this.el = $("<div></div>");
		ArcoObjectView.prototype.initialize.call(this);
		this.render();
		this.doLayout();
		this.listenTo(this.model, "change", this.render);
		debug("creating a view for " + this.model.get("name"));
	},
	render : function() {
		var variables = {
			resource_name : this.model.get("name"),
			resource_amount : this.model.get("amount"),
			resource_production : this.model.get("production"),
			resource_label : this.model.get("label")
		};
		var template = _.template( $("#resource_template").html(), variables);
		this.$el.html( template );
	}
});

ArcoTower = ArcoObject.extend({
	defaults : {
		name : "Tower",
		layout_id : null,
		current_height : 0,
		min_height : 0,
		max_height : 0
	},
	initialize : function() {
		this.view = new ArcoTowerView({ model : this });
		ArcoObject.prototype.initialize.call(this);

		debug("creating a model for " + this.get("name") + " (" + this.get("id") + ")");
	},
	onUpdateHeight : function(evt, amt, other) {
		height = parseInt(amt);
		this.set({ current_height : height });
	}
});

ArcoTowerView = ArcoObjectView.extend({
	initialize : function() {
		this.el = $("<div></div>");
		ArcoObjectView.prototype.initialize.call(this);
		this.render();
		this.doLayout();
		this.listenTo(this.model, "change", this.render);
		debug("creating a view for " + this.model.get("name"));
	},
	render : function() {
		var variables = {
			tower_name : this.model.get("name"),
			tower_height : this.model.get("current_height"),
			tower_min : this.model.get("min_height"),
			tower_max : this.model.get("max_height"),
		};
		var template = _.template( $("#tower_template").html(), variables);
		this.$el.html( template );
	}
});

ArcoWall = ArcoObject.extend({
	defaults : {
		name : "Wall",
		layout_id : null,
		current_height : 0,
		min_height : 0,
		max_height : 0
	},
	initialize : function() {
		this.view = new ArcoWallView({ model : this });
		ArcoObject.prototype.initialize.call(this);
		
		debug("creating a model for " + this.get("name") + " (" + this.get("id") + ")");
	},
	onUpdateHeight : function(evt, amt) {
		var height = parseInt(amt);
		this.set({ current_height : height });
	}
});

ArcoWallView = ArcoObjectView.extend({
	initialize : function() {
		this.el = $("<div></div>");
		ArcoObjectView.prototype.initialize.call(this);
		this.render();
		this.doLayout();
		this.listenTo(this.model, "change", this.render);
		debug("creating a view for " + this.model.get("name"));
	},
	render : function() {
		var variables = {
			wall_name : this.model.get("name"),
			wall_height : this.model.get("current_height"),
			wall_min : this.model.get("min_height"),
			wall_max : this.model.get("max_height"),
		};
		var template = _.template( $("#wall_template").html(), variables);
		this.$el.html( template );
	}
});

ArcoStatus = ArcoObject.extend({
	defaults : {
		state : "Unknown"
	},
	initialize : function() {
		this.view = new ArcoStatusView({ model : this });
		ArcoObject.prototype.initialize.call(this);
	},
	onStateChange : function(obj) {
		var newState = obj.changed.gameState;
		
		if( newState == _gameStates.PLAYER_1_TURN ) {
			this.set({ state : "Player 1" });
		} else if( newState == _gameStates.PLAYER_1_DISCARD ) {
			this.set({ state : "Player 1 Discard" });
		} else if( newState == _gameStates.PLAYER_2_TURN ) {
			this.set({ state : "Player 2" });
		}
	}
});

ArcoStatusView = ArcoObjectView.extend({
	initialize : function() {
		this.el = $("<div></div>");
		ArcoObjectView.prototype.initialize.call(this);
		this.render();
		this.doLayout();
		this.listenTo(this.model, "change:state", this.render);
	},
	render : function() {
		var variables = {
			game_state : this.model.get("state")
		};
		var template = _.template( $("#game_state_template").html(), variables);
		this.$el.html( template );
	}
});

ArcoCard = ArcoObject.extend({
	defaults : {
		name : "ArcoCard",
		playable : false
	},
	initialize : function() {
		var cardDef = this.get("def");
		debug(cardDef);
		this.set({
			name : cardDef.name,
			cost : cardDef.cost,
			text : cardDef.text,
			color : cardDef.color,
			css : cardDef.css,
			func : cardDef.func,
			play_again : cardDef.play_again,
			discard : cardDef.discard,
			discardable : cardDef.discardable,
			playable : false
		});
		this.view = new ArcoCardView({ model : this });
		ArcoObject.prototype.initialize.call(this);
	},
	isPlayable : function(value) {
		if( typeof value != "undefined" ) {
			this.set({ "playable" : value });
		}
		return this.get("playable")
	},
	play : function() {
		debug("playing card");
		this.trigger("play", this);
	},
	discard : function() {
		debug("discarding card");
		this.trigger("discard", this);
	},
	destroy : function() {
		this.view.$el.fadeOut();
		this.trigger("destroy", this);
	},
	evaluate : function(player, opponent) {
		this.get("func").apply(this, [player, opponent]);
	}
});

ArcoCardView = ArcoObjectView.extend({
	initialize : function() {
		ArcoObjectView.prototype.initialize.call(this);
		this.render();
		this.doLayout();
		this.$el.addClass(this.model.get("color"));
		this.$el.addClass(this.model.get("css"));
		this.listenTo(this.model, "change:name change:cost change:text", this.render);
		this.listenTo(this.model, "change:playable", this.playableStateChanged);
		debug("creating a view for " + this.model.get("name"));
	},
	render : function() {
		var variables = {
			card_name : this.model.get("name"),
			card_cost : this.model.get("cost"),
			card_text : this.model.get("text")
		};
		var template = _.template( $("#card_template").html(), variables);
		this.$el.html( template );
	},
	playableStateChanged : function() {
		if( this.model.get("playable") ) {
			this.$el.addClass("playable");
		} else {
			this.$el.removeClass("playable");
		}
	},
	tap : function(obj, e) {
		if( this.model.isPlayable() ) {
			this.model.play();
		}
	},
	taphold : function(obj, e) {
		this.model.discard();
	}
});

ArcoCardCollection = Backbone.Collection.extend({
	model : ArcoCard
});

ArcoDeck = ArcoObject.extend({
	defaults : {
		deckName : null,
		cards : null,
		index : 0
	},
	initialize : function() {
		this.view = new ArcoDeckView({ model : this });
		
		// load the deck
		debug("initializing deck with '" + this.get("deckName") + "' set of cards");
		
		var deckName = this.get("deckName");
		var deckCardList = ArcoDecks[deckName];
		var cards = [];
		
		for( var i=0 ; i<deckCardList.length ; i++ ) {
			var card = {};
			_.extend(card, deckCardList[i]);
			cards.push(card);
		}
		
		this.set({ cards : cards });
		
		ArcoObject.prototype.initialize.call(this);
	},
	shuffle : function() {
		// Fisher-Yates
		var cards = this.get("cards");
		debug("shuffling "  + cards.length + " cards" );
		var i = cards.length, j, tempi, tempj;
		if ( i == 0 ) return false;
		while ( --i ) {
			j = Math.floor( Math.random() * ( i + 1 ) );
			tempi = cards[i];
			tempj = cards[j];
			cards[i] = tempj;
			cards[j] = tempi;
		}
		this.set({ cards : cards });
		debug(cards);
	},
	deal : function(count) {
		if( !count ) count=1;
		var dealt = [];
		var cards = this.get("cards");
		var index = this.get("index");
		for( var i=0 ; i<count ; i++ ) {
			debug(index);
			var cardDef = cards[index];
			var card = new ArcoCard({ layout_id : "arcoCard", def : cardDef });
			dealt.push(card);
			index++;
			if( index>=cards.length ) {
				this.shuffle();
				cards = this.get("cards");
				index = 0;
			}
			this.set({ index : index });
		}
		return dealt;
	}
});

ArcoDeckView = ArcoObjectView.extend({
	initialize : function() {
		this.el = $("<div></div>");
		ArcoObjectView.prototype.initialize.call(this);
		this.render();
		this.doLayout();
		this.listenTo(this.model, "change", this.render);
		debug("creating a view for " + this.model.get("name"));
	},
	render : function() {
		var variables = {
		};
		var template = _.template( $("#deck_template").html(), variables);
		this.$el.html( template );
	}
});

ArcoHand = Backbone.Collection.extend({
	pickup : function(card) {
		debug("adding " + card.get("name") + " to hand");
		this.push(card);
		this.trigger("cardDealt", { card : card, position : this.length-1 });
	}
});

ArcoPlayer = Backbone.Model.extend({
	defaults : {
		deck : null,
		hand : null,
		quarry : 0,
		bricks : 0,
		magic : 0,
		gems : 0,
		dungeon : 0,
		recruits : 0,
		tower : 0,
		wall : 0
	},
	initialize : function() {
		this.set({
			deck : new ArcoDeck({ name : this.get("name") + " Deck", layout_id : this.get("layout_id") + "Deck", deckName : "Basic" }),
			hand : new ArcoHand()
		});
	},
	deal : function() {
		var handSize = _settings.get("handSize");
		var hand = this.get("hand");
		while( hand.length < handSize ) {
			var card = _.first(this.get("deck").deal());
			//card.set({ layout_id : this.get("layout_id") + "ArcoCard" });
			hand.pickup(card);
		}
		this.set({ hand : hand });
	},
	removeCard : function(card) {
		var hand = this.get("hand");
		hand.remove(card);
		debug(hand);
		this.set({ hand : hand });
	},
	addQuarry : function(amt) { this.set({ quarry : Math.max(1, (parseInt(this.get("quarry")) + parseInt(amt))) }) },
	addBricks : function(amt) { this.set({ bricks : Math.max(0, (parseInt(this.get("bricks")) + parseInt(amt))) }) },
	addMagic : function(amt) { this.set({ magic : Math.max(1, (parseInt(this.get("magic")) + parseInt(amt))) }) },
	addGems : function(amt) { this.set({ gems : Math.max(0, (parseInt(this.get("gems")) + parseInt(amt))) }) },
	addDungeon : function(amt) { this.set({ dungeon : Math.max(1, (parseInt(this.get("dungeon")) + parseInt(amt))) }) },
	addRecruits : function(amt) { this.set({ recruits : Math.max(0, (parseInt(this.get("recruits")) + parseInt(amt))) }) },
	addTower : function(amt) { this.set({ tower : Math.max(0, (parseInt(this.get("tower")) + parseInt(amt))) }) },
	addWall : function(amt) { this.set({ wall : Math.max(0, (parseInt(this.get("wall")) + parseInt(amt))) }) },
	takeDamage : function(amt) {
		amt = parseInt(amt);
		var wall = parseInt(this.get("wall"));
		var tower = parseInt(this.get("tower"));
		
		if( amt > wall ) {
			amt -= wall;
			wall = 0;
		} else {
			wall -= amt;
			amt = 0;
		}
		
		tower -= amt;
		
		tower = Math.max(0, tower);
		
		this.set({
			wall : wall,
			tower : tower
		});
	},
	charge : function(obj) {
		debug("charging " + obj.color + ":" + obj.cost);
		if( obj.color=="red" ) this.addBricks(-obj.cost);
		if( obj.color=="blue" ) this.addGems(-obj.cost);
		if( obj.color=="green" ) this.addRecruits(-obj.cost);
	},
	setPlayableCards : function(force) {
		var hand = this.get("hand");
		for( var i=0 ; i<hand.length ; i++ ) {
			if( typeof force != "undefined") {
				var card = hand.at(i);
				card.set({ playable : force });
			} else {
				var card = hand.at(i);
				var playable = true;
				if( card.get("color") == "red" && parseInt(card.get("cost")) > parseInt(this.get("bricks")) ) playable = false;
				if( card.get("color") == "blue" && parseInt(card.get("cost")) > parseInt(this.get("gems")) ) playable = false;
				if( card.get("color") == "green" && parseInt(card.get("cost")) > parseInt(this.get("recruits")) ) playable = false;
				card.set({ playable : playable });
			}
		}
	},
	addResources : function() {
		var quarry = parseInt(this.get("quarry"));
		var magic = parseInt(this.get("magic"));
		var dungeon = parseInt(this.get("dungeon"));
		
		this.addBricks(quarry);
		this.addGems(magic);
		this.addRecruits(dungeon);
	}
});

ArcoCPUPlayer = ArcoPlayer.extend({
	play : function() {
		debug("CPU playing");
		
		// TODO: insert awesome AI here
		var card = this.get("hand").at(0);
		this.trigger("play", card);
	},
	discard : function() {
		debug("CPU discarding");
		
		// TODO: more fancy logic here
		var card = this.get("hand").at(0);
		this.trigger("discard", card);
	}
});

ArcoGameConditions = Backbone.NestedModel.extend({
	defaults : {
		initial : {
			player1 : {
				quarry : 1,
				bricks : 5,
				magic : 1,
				gems : 5,
				dungeon : 1,
				recruits : 5,
				tower : 10,
				wall : 5
			},
			player2 : {
				quarry : 2,
				bricks : 10,
				magic : 2,
				gems : 10,
				dungeon : 2,
				recruits : 10,
				tower : 20,
				wall : 10
			}
		},
		win : {
			tower : 100
		}
	}
});

var _gameStates = {
	UNINITIALIZED : "Unitialized",
	NEW_GAME : "New Game",
	PLAYER_1_TURN : "Player 1 Turn",
	PLAYER_1_TURN_END : "Player 1 Turn End",
	PLAYER_1_DISCARD : "Player 1 Discard",
	PLAYER_2_TURN : "Player 2 Turn",
	PLAYER_2_TURN_END : "Player 2 Turn End",
	ANIMATING : "Animating"
};

ArcoGame = Backbone.Model.extend({
	defaults : {
		discardPile : [],
		play_again : false,
		gameState : _gameStates.UNITIALIZED
	},
	initialize : function() {
		this.view = new ArcoGameView({ model : this });
		
		this.player1 = new ArcoPlayer({ name : "Player 1", layout_id : "player1" });
		this.view.addElement(this.player1.get("deck"));
		this.listenTo(this.player1.get("hand"), "cardDealt", this.onPlayer1CardDealt);
		
		this.player2 = new ArcoCPUPlayer({ name : "Player 2" });
		
		this.player1Quarry = new ArcoResource({ name : "Player 1 Quarry", layout_id : "player1Quarry", label : "Bricks" });
		this.player1Quarry.listenTo(this.player1, "change:quarry", this.player1Quarry.onUpdateProduction);
		this.player1Quarry.listenTo(this.player1, "change:bricks", this.player1Quarry.onUpdateAmount);
		this.view.addElement(this.player1Quarry);
		
		this.player1Magic = new ArcoResource({ name : "Player 1 Magic", layout_id : "player1Magic", label : "Gems" });
		this.player1Magic.listenTo(this.player1, "change:magic", this.player1Magic.onUpdateProduction);
		this.player1Magic.listenTo(this.player1, "change:gems", this.player1Magic.onUpdateAmount);
		this.view.addElement(this.player1Magic);
		
		this.player1Dungeon = new ArcoResource({ name : "Player 1 Dungeon", layout_id : "player1Dungeon", label : "Recruits" });
		this.player1Dungeon.listenTo(this.player1, "change:dungeon", this.player1Dungeon.onUpdateProduction);
		this.player1Dungeon.listenTo(this.player1, "change:recruits", this.player1Dungeon.onUpdateAmount);
		this.view.addElement(this.player1Dungeon);
		
		this.player1Tower = new ArcoTower({ name : "Player 1 Tower", layout_id : "player1Tower" });
		this.player1Tower.listenTo(this.player1, "change:tower", this.player1Tower.onUpdateHeight);
		this.view.addElement(this.player1Tower);
		
		this.player1Wall = new ArcoWall({ name : "Player 1 Wall", layout_id : "player1Wall" });
		this.player1Wall.listenTo(this.player1, "change:wall", this.player1Wall.onUpdateHeight);
		this.view.addElement(this.player1Wall);
		
		this.player2Quarry = new ArcoResource({ name : "Player 2 Quarry", layout_id : "player2Quarry", label : "Bricks" });
		this.player2Quarry.listenTo(this.player2, "change:quarry", this.player2Quarry.onUpdateProduction);
		this.player2Quarry.listenTo(this.player2, "change:bricks", this.player2Quarry.onUpdateAmount);
		this.view.addElement(this.player2Quarry);
		
		this.player2Magic = new ArcoResource({ name : "Player 2 Magic", layout_id : "player2Magic", label : "Gems" });
		this.player2Magic.listenTo(this.player2, "change:magic", this.player2Magic.onUpdateProduction);
		this.player2Magic.listenTo(this.player2, "change:gems", this.player2Magic.onUpdateAmount);
		this.view.addElement(this.player2Magic);
		
		this.player2Dungeon = new ArcoResource({ name : "Player 2 Dungeon", layout_id : "player2Dungeon", label : "Recruits" });
		this.player2Dungeon.listenTo(this.player2, "change:dungeon", this.player2Dungeon.onUpdateProduction);
		this.player2Dungeon.listenTo(this.player2, "change:recruits", this.player2Dungeon.onUpdateAmount);
		this.view.addElement(this.player2Dungeon);
		
		this.player2Tower = new ArcoTower({ name : "Player 2 Tower", layout_id : "player2Tower" });
		this.player2Tower.listenTo(this.player2, "change:tower", this.player2Tower.onUpdateHeight);
		this.view.addElement(this.player2Tower);
		
		this.player2Wall = new ArcoWall({ name : "Player 2 Wall", layout_id : "player2Wall" });
		this.player2Wall.listenTo(this.player2, "change:wall", this.player2Wall.onUpdateHeight);
		this.view.addElement(this.player2Wall);
		
		this.status = new ArcoStatus({ name  : "Status", layout_id : "gameState" });
		this.status.listenTo(this, "change:gameState", this.status.onStateChange);
		this.view.addElement(this.status);
		
		this.player1Hand = new ArcoHand();
		this.player2Hand = new ArcoHand();
	},
	setState : function(state) {
		this.set({ gameState : state });
	},
	getState : function() {
		return this.get("gameState");
	},
	isState : function(state) {
		return this.get("gameState") === state;
	},
	onPlayer1CardDealt : function(e) {
		var card = e.card;
		var position = e.position;
		debug("card '" + e.card.get("name") + "' dealt to position " + position);
		var self=this;
		card.on("play", function() { self.onPlayer1Play(this) });
		card.on("discard", function() { self.onPlayer1Discard(this) });
		card.on("destroy", function() { self.onCardDestroy(this); });
		this.view.addElement(card);
		this.player1.setPlayableCards();
		
		var options = {
			callback : function() {
				//self.player1.setPlayableCards();
			}
		}
		_.extend(options, _layout.get("player1Cards")[position]);
		
		card.view.moveTo( options );
	},
	onCardDestroy : function(card) {
		this.view.removeElement(card);
	},
	onPlayer1Play : function(card) {
		if( !card.isPlayable() || !this.isState(_gameStates.PLAYER_1_TURN) ) return;
		
		this.setState(_gameStates.ANIMATING);
		
		// charge cost, update hand status, set status to played to prevent multiple clicking or playing from discard
		this.player1.charge({
			color : card.get("color"), 
			cost : card.get("cost")
		});
		this.player1.setPlayableCards();
		debug("player1 card played");
		card.set({ playable : false });
		this.player1.removeCard(card);
		this.fixPlayer1Cards();
		var position = _layout.get("cardPlay").position;

		//  move it to the play position, then discard
		this.playCard(card, this.player1, this.player2);
		this.player1.deal();
		
		if( card.get("play_again") ) {
			this.set({ play_again : true });
		}
		
		var self = this;
		_.delay( function() {
			if( card.get("discard") ) {
				self.setState(_gameStates.PLAYER_1_DISCARD);
			} else {
				self.setState(_gameStates.PLAYER_1_TURN_END);
			}
		}, 900);
	},
	onPlayer1Discard : function(card) {
		if( (!this.isState(_gameStates.PLAYER_1_TURN) && !this.isState(_gameStates.PLAYER_1_DISCARD)) ) return;
		if( !card.get("discardable") ) {
			debug("can't discard this card");
			return;
		}
		
		this.setState(_gameStates.ANIMATING);
		
		this.player1.removeCard(card);
		this.fixPlayer1Cards();
		this.player1.deal();
		this.discardCard(card);
		
		ArcoSounds.Deal.playclip();
		
		var self = this;
		_.delay( function() { self.setState(_gameStates.PLAYER_1_TURN_END) }, 900 );
	},
	onPlayer2Play : function(card) {
		this.setState(_gameStates.ANIMATING);
		
		// do stuff that normally would've been done for player1 when the card was dealt
		card.on("destroy", function() { self.onCardDestroy(this); });
		this.view.addElement(card);
		var position = _layout.get("player2CardPlay.position");
		debug("moving to");
		var options  = _.extend({
			duration : 0
		}, position);
		debug(options);
		card.view.moveTo(options);
		
		// charge cost, update hand status, set status to played to prevent multiple clicking or playing from discard
		this.player2.charge({
			color : card.get("color"), 
			cost : card.get("cost")
		});
		debug("player2 card played");
		card.set({ playable : false });
		this.player2.removeCard(card);
		var position = _layout.get("cardPlay").position;

		//  move it to the play position, then discard
		this.playCard(card, this.player2, this.player1);
		this.player2.deal();
		
		if( card.get("play_again") ) {
			this.set({ play_again : true });
		}
		
		var self = this;
		_.delay( function() {
			if( card.get("discard") ) {
				self.setState(_gameStates.PLAYER_2_DISCARD);
			} else {
				self.setState(_gameStates.PLAYER_2_TURN_END);
			}
		}, 900);
	},
	onPlayer2Discard : function(card) {
		this.setState(_gameStates.ANIMATING);
		
		this.player2.removeCard(card);
		
		card.on("destroy", function() { self.onCardDestroy(this); });
		this.view.addElement(card);
		var position = _layout.get("player2CardPlay.position");
		debug("moving to");
		var options  = _.extend({
			duration : 0
		}, position);
		debug(options);
		card.view.moveTo(options);
		
		this.player2.deal();
		
		this.discardCard(card);
		
		ArcoSounds.Deal.playclip();
		
		var self = this;
		_.delay( function() { self.setState(_gameStates.PLAYER_2_TURN_END) }, 900 );
	},
	fixPlayer1Cards : function(options) {
		var hand = this.player1.get("hand");
		if( typeof options == "undefined" ) options = {};
		$.each(hand.toArray(), function(index, card) {
			_.extend(options, _layout.get("player1Cards")[index]);
			card.view.moveTo( options );
		});
	},
	fixDiscardPile : function(options) {
		var size = _settings.get("discardPileSize");
		var discardPile = this.get("discardPile");
		var positions = _layout.get("discardCards");
		if( typeof options == "undefined" ) options = {};
		debug("fixing  discard pile");
		$.each(discardPile, function(index, card) {
			debug("moving " + card.get("name"));	
			_.extend(options, positions[size - discardPile.length + index]);
			card.view.moveTo(options);
		});
	},
	playCard : function(card, player, opponent) {
		var position = _layout.get("cardPlay").position;
		var options = {
			duration : 500,
			callback : function() {
				card.evaluate(player, opponent);
			}
		};
		
		_.extend(options, position);
		card.view.moveTo(options);
		var self=this;
		_.delay(function() { self.discardCard(card) }, 600);
	},
	discardCard : function(card) {
		var discardPile = this.get("discardPile");
		var discardPileSize = _settings.get("discardPileSize");
		var positions = _layout.get("discardCards");
		
		// make sure card is unplayable
		card.set({ playable : false });
		this.stopListening(card);
		card.view.tap = function() {};
		card.view.taphold = function() {};
		
		// get rid of the
		if( discardPile.length >= discardPileSize ) {
			var trashCard = _.first(discardPile);
			discardPile = _.rest(discardPile);
			
			if( typeof trashCard != undefined ) {
				debug("destroying " + trashCard.get("name"));
				trashCard.destroy();
			}
		}

		// add new card to the pile and "fix"
		discardPile.push(card);
		this.set({ discardPile : discardPile });
		this.fixDiscardPile();
	},
	newGame : function(conditions) {
		if( typeof conditions == "undefined" ) {
			conditions =  new ArcoGameConditions();
		}
		// initialize resources, towers, walls, decks, hands
		this.player1.set({ bricks : conditions.get("initial.player1.bricks") });
		this.player1.set({ quarry : conditions.get("initial.player1.quarry") });
		this.player1.set({ magic : conditions.get("initial.player1.magic") });
		this.player1.set({ gems : conditions.get("initial.player1.gems") });
		this.player1.set({ dungeon : conditions.get("initial.player1.dungeon") });
		this.player1.set({ recruits : conditions.get("initial.player1.recruits") });
		this.player1.set({ tower : conditions.get("initial.player1.tower") });		
		this.player1.set({ wall : conditions.get("initial.player1.wall") });
		
		this.player2.set({ bricks : conditions.get("initial.player2.bricks") });
		this.player2.set({ quarry : conditions.get("initial.player2.quarry") });
		this.player2.set({ magic : conditions.get("initial.player2.magic") });
		this.player2.set({ gems : conditions.get("initial.player2.gems") });
		this.player2.set({ dungeon : conditions.get("initial.player2.dungeon") });
		this.player2.set({ recruits : conditions.get("initial.player2.recruits") });
		this.player2.set({ tower : conditions.get("initial.player2.tower") });
		this.player2.set({ wall : conditions.get("initial.player2.wall") });
		
		this.player1.get("deck").shuffle();
		this.player2.get("deck").shuffle();
		//ArcoSounds.Deal.playclip();
		this.player1.deal();
		this.player2.deal();
		
		this.listenTo(this.player2, "play", this.onPlayer2Play);
		this.listenTo(this.player2, "discard", this.onPlayer2Discard);
		
		this.on("change:gameState", this.onGameStateChange);
		
		this.setState(_gameStates.PLAYER_1_TURN);
	},
	onGameStateChange : function() {
		if( this.isState(_gameStates.PLAYER_1_TURN) ) {
			trace("STATE: PLAYER_1_TURN");
			this.player1.addResources();
			this.player1.setPlayableCards();
		} else if( this.isState(_gameStates.PLAYER_1_TURN_END) ) {
			trace("STATE: PLAYER_1_TURN_END");
			if( this.get("play_again") ) {
				this.set({ "play_again" : false });
				this.setState(_gameStates.PLAYER_1_TURN);
			} else {
				this.setState(_gameStates.PLAYER_2_TURN);
			}
		} else if( this.isState(_gameStates.PLAYER_1_DISCARD) ) {
			trace("STATE: PLAYER_1_DISCARD");
			this.player1.setPlayableCards(false);
		} else if( this.isState(_gameStates.PLAYER_2_TURN) ) {
			trace("STATE: PLAYER_2_TURN");
			this.player2.addResources();
			this.player2.play();
		} else if( this.isState(_gameStates.PLAYER_2_DISCARD) ) {
			trace("STATE: PLAYER_2_DISCARD");
			this.player2.discard();
		} else if( this.isState(_gameStates.PLAYER_2_TURN_END) ) {
			trace("STATE: PLAYER_2_TURN_END");
			
			if( this.get("play_again") ) {
				this.set({ "play_again" : false });
				this.setState(_gameStates.PLAYER_2_TURN);
			} else {
				this.setState(_gameStates.PLAYER_1_TURN);
			}
		} else if( this.isState(_gameStates.ANIMATING) ) {
			trace("STATE: ANIMATING");
		} else if( this.isState(_gameStates.NEW_GAME) ) {
			trace("STATE: NEW_GAME");
		}
	},
	destroy : function() {
		this.view.destroy();
	}
});

ArcoGameView = Backbone.View.extend({
	el : $("<div></div>"),
	elements : new ArcoElements(),
	initialize : function() {
		this.$el.css({
			"width" : "100%",
			"height" : "100%",
			"position" : "absolute",
			"textShadow" : "none"
		});
		this.$el.appendTo($("#game-view"));
	},
	render : function() {
	},
	addElement : function(el) {
		this.$el.append(el.view.$el);
		this.elements.push(el);
	},
	removeElement : function(el) {
		this.elements.remove(el);
		debug("card removed, " + this.elements.length + " elements remain");
	},
	destroy : function() {
		this.$el.remove();
	}
});

$(document).bind("mobileinit", function(){
	debug("mobileinit");
});

$(window).bind("resize", function() {
	_layout.calculate();
});

var _game;

$(document).delegate("#game-view", "pageinit", function() {
	_game = new ArcoGame();
	_game.newGame();
	_layout.calculate();
});